#include<iostream>
#include"Types.hpp"
#include"Lattice.hpp"
#include<vector>
#include<iostream>
#include<fstream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>

extern "C" {
#include <pgm.h>
}

//functions defined in this file
void readParams(const std::string& fileName,uint& sizex,uint& sizey,uint& tstep,double& omg,std::string& vtk_file, uint& vtk_step, std::string& pgm_file);
//void readpgm(const std::string& filename, uint &xsize_, uint &ysize_);

int main(int argc, char *argv[])
{
	uint sizex, sizey, tstep, vtk_step;
	real omg;
	std::string vtk_file, pgm_file="";


	//flag for simulation
	//bool sim = 0;
	if(argc == 1)
	{
		std::cout << "Parameter file missing!" << std::endl;
		return 0;
	}
	readParams(argv[1],sizex,sizey,tstep,omg,vtk_file,vtk_step, pgm_file);
	//	std::cout<<"lengthx: "<<sizex<<"\n";
	//	std::cout<<"lengthy: "<<sizey<<"\n";
	Lattice *lbmLattice;
	if (pgm_file.empty())
		lbmLattice = new Lattice(sizex+2,sizey+2,omg);
	else
		lbmLattice = new Lattice(omg, pgm_file);


	(*lbmLattice).initialize(1.0,0.0,0.0);
	//To be change for the actual values
	real vwx=0.01, vwy=0.0;
	for(uint t=0;t<tstep;++t)
	{
		//lbmLattice.streaming(vwx,vwy);
		//lbmLattice.collision();
		(*lbmLattice).streamingCollision(vwx,vwy);
		//lbmLattice.swapPDFsGrids();
		(*lbmLattice).copyGrid();
		std::string print = vtk_file + std::to_string(t);
		(*lbmLattice).printF(print);
	}
	//lbmLattice.checkMaps();

	return 0;
}


std::vector<std::string> tokenize(const char* str, const char* delim)
{
	std::vector<std::string> tokens;
	char* token = strtok (const_cast<char*>(str), const_cast<char*>(delim));
	while (token != NULL) {
		tokens.push_back(token);
		token = strtok (NULL, delim);
	}
	return tokens;
}

//method to read input file with parameter values
void readParams(const std::string& fileName,uint& sizex,uint& sizey,uint& tstep,double& omg,std::string& vtk_file, uint& vtk_step, std::string& pgm_file) {
	std::ifstream infile(fileName.c_str(), std::ios::in);
	const int max_chars_per_line = 512;
	char *buffer(new char[max_chars_per_line]);
	std::vector<std::string> tokens;
	if(!(infile.is_open() && infile.good()))
	{
		std::cerr << std::endl;
		std::cerr << "ERROR: Failed to open file: " << fileName << std::endl;
		std::cerr << std::endl;
		infile.close();
		return;
	}
	int i=0;
	//for (int i = 0; i < 7; ++i)
	while (!infile.eof())
	{
		std::cout <<i<< std::endl;
		infile.getline(buffer, max_chars_per_line);
		tokens = tokenize(buffer, " \t\r\n");
		uint n_tokens = tokens.size();
		if (n_tokens ==0) { ++i; continue;}
		switch(i)
		{
		case 0:
			sizex = atoi(tokens[1].c_str());
			++i;
			break;
		case 1:
			sizey = atoi(tokens[1].c_str());
			++i;
			break;
		case 2:
			tstep = atoi(tokens[1].c_str());
			++i;
			break;
		case 3:
			omg = atof(tokens[1].c_str());
			++i;
			break;
		case 4:
			vtk_file = tokens[1];
			++i;
			break;
		case 5:
			vtk_step = atoi(tokens[1].c_str());
			++i;
			break;
		case 6:			
			pgm_file =tokens[1];
			break;
		}
	}
	//    std::cout << "sizex: " << sizex << "\nsizey: " << sizey << "\ntstep:" << tstep << "\nomg: " << omg << "\nvtk_file: " << vtk_file << "\nvtk_step: " << vtk_step << std::endl;
}

/*
void readpgm(const std::string& filename, uint &xsize_, uint &ysize_)
{
//int    xsize_;   // Number of pixels in x-direction should be equal to imax+2
//int    ysize_;   // Number of pixels in y-direction should be equal to jmax+2
gray maxval_;
gray** image_;
FILE* pgmFile;

pgmFile=fopen(filename.c_str(),"r");                                                                                        
if(pgmFile==NULL){
std::cout<<"Error Reading the pgm file.";
exit(1);
}
image_ = pgm_readpgm( pgmFile, &xsize_, &ysize_, &maxval_ );

std::cout<<xsize_<<" "<<ysize_<<"\n";


for(int i=0;i<xsize_;++i)
{
for(int j=0;j<ysize_;++j)
{
std::cout<<image_[i][j]<<" ";
if (image_[i][(ysize_-1)-j] == maxval_)
(*FLAG_)(i,j)=1;
else (*FLAG_)(i,j)=0;
}
std::cout<<std::endl;
}

std::cout<<std::endl;

fclose(pgmFile);
pgm_freearray(image_,ysize_);

}


void readmatrix(const std::string& filename, uint &x_size, uint &y_size)
{
std::ifstream matrix_reader(filename);

if (matrix_reader.is_open())
{
std::string name;
int max_value;
matrix_reader >> name >> x_size >> y_size >> max_value;
for (int j = y_size-1; j >=0; --j) 
{
for (int i = 0; i < x_size; ++i) 
{
matrix_reader >> (*FLAG_)(i,j);
}

}

for ( int p = 0; p <=imax_d+1; ++p)
{
(*FLAG_)(p,0)=C_B;
(*FLAG_)(p,jmax_d+1)=C_B;
}

for ( int q = 0; q <=jmax_d+1; ++q)
{
(*FLAG_)(0,q)=C_B;
(*FLAG_)(imax_d+1,q)=C_B;
}
}
}*/